﻿using ArtMath.Attribute;
using ArtMath.Control;
using ArtMath.Core.Helper;
using ArtMath.Flag;
using ArtMath.CommonType;
using ArtMath.Parameter;
using ArtMath.Resource;
using ArtMath.Setting;
using ArtMath.Window;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Timers;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;

namespace ArtMath
{
    /// <summary>
    /// 文档（画板的集合）
    /// </summary>
    [Serializable]
    public class Document : IName, CommonType.ISerializable, IActivate
    {
        public class StatusChangedEventArgs : EventArgs
        {
            public string Status { get; }
            public bool IsAppend { get; }
            public StatusChangedEventArgs(string status, bool append)
            {
                Status = status;
                IsAppend = append;
            }
        }
        public enum SaveReason
        {
            UserSave,
            AutoSave,
        }
        [NonSerialized]
        FileStream linkedFile;
        [Browsable(false)]
        public FileStream LinkedFile
        {
            get { return linkedFile; }
            set
            {
                linkedFile = value;
                if (linkedFile != null)
                {
                    lblLocation.Text = linkedFile.Name;
                }
            }
        }
        string title, remark;
        [NonSerialized]
        ListViewItem documentsManagerItem;
        [Browsable(false)]
        public ListViewItem DocumentsManagerItem { get { return documentsManagerItem; } }
        [NonSerialized]
        ToolStripMenuItem windowMenuItem;
        [Browsable(false)]
        public ToolStripMenuItem WindowMenuItem { get { return windowMenuItem; } }
        [NonSerialized]
        DocumentWindow documentWindow;
        [Browsable(false)]
        public DocumentWindow DocumentWindow { get { return documentWindow; } }
        [Browsable(false)]
        public List<SketchPad> Pads { get; } = new List<SketchPad>();
        [Browsable(false)]
        public List<BasicParameter> Parameters { get; } = new List<BasicParameter>();
        [Browsable(false)]
        public SketchPad SelectedPad { get; private set; }
        [Browsable(false)]
        public bool IsActivated { get; private set; }
        public event Action<Document> Activated, TitleChanged;
        public event Action NoSketchPadSelected;
        bool changed;
        readonly object saveLocker = new object();
        #region HomePageControls
        [NonSerialized]
        TableLayoutPanel homePageLayout;
        [NonSerialized]
        ListView thumbNailList;
        [Browsable(false)]
        public ListView ThumbNailList { get { return thumbNailList; } }
        [NonSerialized]
        ImageList imageList;
        [NonSerialized]
        TabControl pageContainer;
        [Browsable(false)]
        public TabControl PageContainer { get { return pageContainer; } }
        [NonSerialized]
        TabPage homePage;
        [NonSerialized]
        Label lblTitle;
        [NonSerialized]
        LinkLabel lblLocation;
        [NonSerialized]
        Button btnAddPad, btnDelPad, btnPrint, btnGoTo;
        [Browsable(false)]
        public Button AddSketchpadButton { get { return btnAddPad; } }
        [NonSerialized]
        TextBox tbRemark;
        #endregion
        public Document(string title)
        {
            documentWindow = new DocumentWindow(this);
            buildHomePage(title);
            documentsManagerItem = new ListViewItem(new string[] { title, string.Empty }) { Tag = this };
            windowMenuItem = new ToolStripMenuItem(title, null)
            {
                CheckOnClick = true,
                Tag = true,//指示是否触发CheckedChanged事件
            };
            Title = title;
        }
        void buildHomePage(string title)
        {
            imageList = new ImageList()
            {
                ImageSize = new Size(256, 144),
                ColorDepth = ColorDepth.Depth32Bit,
            };
            //选项卡集合
            pageContainer = new TabControl()
            {
                Dock = DockStyle.Fill,
                Alignment = Settings.Instance.TabLocation,
            };
            PageContainer.SelectedIndexChanged += TabControl_IndexChanged;
            PageContainer.DoubleClick += TabControl_DoubleClick;
            //首页选项卡
            homePage = new TabPage()
            {
                Text = Resources.Translate("HomePage"),
                BackColor = Color.White,
            };
            //布局
            homePageLayout = new TableLayoutPanel()
            {
                RowCount = 5,
                ColumnCount = 4,
                Dock = DockStyle.Fill,
            };
            homePage.Controls.Add(homePageLayout);
            //标题标签
            lblTitle = new Label()
            {
                Text = title,
                Font = new Font("Microsoft YaHei", 30),
                AutoEllipsis = true,
                Dock = DockStyle.Fill,
                TextAlign = ContentAlignment.MiddleLeft,
            };
            homePageLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            homePageLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 10));
            homePageLayout.Controls.Add(lblTitle, 0, 0);
            homePageLayout.SetColumnSpan(lblTitle, homePageLayout.ColumnCount);
            //存储位置链接标签
            lblLocation = new LinkLabel()
            {
                Font = new Font("Microsoft YaHei", 20),
                AutoEllipsis = true,
                Dock = DockStyle.Fill,
                TextAlign = ContentAlignment.MiddleLeft,
            };
            lblLocation.LinkClicked += (object sender, LinkLabelLinkClickedEventArgs e) =>
            {
                if (LinkedFile == null) return;
                Utility.ExploreFile(LinkedFile.Name);
            };
            homePageLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            homePageLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 5));
            homePageLayout.Controls.Add(lblLocation, 0, 1);
            homePageLayout.SetColumnSpan(lblLocation, homePageLayout.ColumnCount);
            //添加画板按钮
            btnAddPad = new Button()
            {
                Text = Resources.JoinLocalizedString("Add", "Sketchpad"),
                UseVisualStyleBackColor = true,
                Dock = DockStyle.Fill,
                Image = Resource.Properties.Resources.add_24x,
                TextImageRelation = TextImageRelation.ImageBeforeText,
                TextAlign = ContentAlignment.MiddleRight,
                Tag = this,
            };
            homePageLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 5));
            homePageLayout.Controls.Add(btnAddPad, 0, 2);
            //删除画板按钮
            btnDelPad = new Button()
            {
                Text = Resources.JoinLocalizedString("Delete", "Sketchpad"),
                UseVisualStyleBackColor = true,
                Dock = DockStyle.Fill,
                Image = Resource.Properties.Resources.delete_24x,
                TextImageRelation = TextImageRelation.ImageBeforeText,
                TextAlign = ContentAlignment.MiddleRight,
                Enabled = false,
            };
            btnDelPad.Click += (object sender, EventArgs e) =>
            {
                DeleteSketchpads();
            };
            homePageLayout.Controls.Add(btnDelPad, 1, 2);
            //打印按钮
            btnPrint = new Button()
            {
                Text = Resources.Translate("Print"),
                UseVisualStyleBackColor = true,
                Dock = DockStyle.Fill,
                Image = Resource.Properties.Resources.print_24x,
                TextImageRelation = TextImageRelation.ImageBeforeText,
                TextAlign = ContentAlignment.MiddleRight,
                Enabled = false,
            };
            btnPrint.Click += (object sender, EventArgs e) =>
            {
                foreach (ListViewItem item in thumbNailList.SelectedItems)
                {
                    SketchPad pad = item.Tag as SketchPad;
                    pad.Print();
                }
            };
            homePageLayout.Controls.Add(btnPrint, 2, 2);
            //转到按钮
            btnGoTo = new Button()
            {
                Text = Resources.Translate("GoTo"),
                UseVisualStyleBackColor = true,
                Dock = DockStyle.Fill,
                Image = Resource.Properties.Resources._goto,
                TextImageRelation = TextImageRelation.ImageBeforeText,
                TextAlign = ContentAlignment.MiddleRight,
                Enabled = false,
            };
            btnGoTo.Click += gotoSelectedPad;
            homePageLayout.Controls.Add(btnGoTo, 3, 2);
            //画板列表
            thumbNailList = new ListView()
            {
                View = View.LargeIcon,
                LargeImageList = imageList,
                Dock = DockStyle.Fill,
                LabelEdit = true,
            };
            thumbNailList.ItemActivate += gotoSelectedPad;
            thumbNailList.SelectedIndexChanged += (object sender, EventArgs e) =>
            {
                btnDelPad.Enabled = btnPrint.Enabled = thumbNailList.SelectedItems.Count > 0;
                btnGoTo.Enabled = thumbNailList.SelectedItems.Count == 1;
            };
            thumbNailList.AfterLabelEdit += (object sender, LabelEditEventArgs e) =>
            {
                SketchPad pad = thumbNailList.Items[e.Item].Tag as SketchPad;
                pad.Name = e.Label;
            };
            homePageLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            homePageLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 70));
            homePageLayout.Controls.Add(thumbNailList, 0, 3);
            homePageLayout.SetColumnSpan(thumbNailList, homePageLayout.ColumnCount);
            //备注文本框
            tbRemark = new PlaceHolderTextBox()
            {
                Multiline = true,
                ScrollBars = ScrollBars.Vertical,
                Dock = DockStyle.Fill,
                PlaceHolderText = Resources.Translate("Remark"),
            };
            tbRemark.Validated += (object sender, EventArgs e) =>
            {
                Remark = tbRemark.Text;
            };
            homePageLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            homePageLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 10));
            homePageLayout.Controls.Add(tbRemark, 0, 4);
            homePageLayout.SetColumnSpan(tbRemark, homePageLayout.ColumnCount);
            PageContainer.TabPages.Add(homePage);
            DocumentWindow.Controls.Add(PageContainer);
        }
        public void DeleteSketchpads(bool all = false)
        {
            bool sft = Flags.Shift;
            if (sft)
            {
                if (MessageBox.Show(string.Format(Resources.Translate("DeleteObjectAsk"), Resources.Translate("Sketchpad")), Resources.Translate("Ask"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
                {
                    return;
                }
            }
            foreach (ListViewItem item in thumbNailList.GetItems(all))
            {
                SketchPad pad = item.Tag as SketchPad;
                try
                {
                    pad.Delete(!sft);
                }
                catch (Exception)
                {
                    MessageBox.Show(string.Format(Resources.Translate("DeleteUsingParameter"), pad.Name), Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            if (thumbNailList.Items.Count > 0)
            {
                thumbNailList.Items[0].Selected = true;
            }
        }
        void gotoSelectedPad(object sender, EventArgs e)
        {
            (thumbNailList.SelectedItems[0].Tag as SketchPad).Activate();
        }
        [Browsable(false)]
        public bool Modified
        {
            get { return changed; }
            set
            {
                if (changed == value) return;
                changed = value;
                changeControlTitle();
            }
        }
        [MultilingualCategory("Basic"), MultilingualDisplayName("Remark")]
        public string Remark
        {
            get { return remark; }
            set
            {
                if (remark == value) return;
                remark = value;
                tbRemark.Text = DocumentsManagerItem.SubItems[1].Text = remark;
            }
        }
        [MultilingualCategory("Basic"), MultilingualDisplayName(null, "Document", "Title")]
        public string Title
        {
            get { return title; }
            set
            {
                if (title == value) return;
                title = value;
                lblTitle.Text = title;
                changeControlTitle();
                TitleChanged?.Invoke(this);
            }
        }
        [Browsable(false)]
        public string Name
        {
            get { return Title; }
        }
        void changeControlTitle()
        {
            string str = Title + (Modified ? "*" : string.Empty);
            DocumentWindow.CrossThreadInvoke(() => { DocumentWindow.Text = str; });
            DocumentsManagerItem.ListView.CrossThreadInvoke(() => { DocumentsManagerItem.SubItems[0].Text = str; });
            WindowMenuItem.Owner.CrossThreadInvoke(() => { WindowMenuItem.Text = str; });
        }
        void TabControl_DoubleClick(object sender, EventArgs e)
        {
            if (PageContainer.SelectedTab != homePage)
            {
                SketchPad pad = PageContainer.SelectedTab.Tag as SketchPad;
                if (UIInteraction.Rename.Rename(pad.Name, CheckPadNameExist, (string newName) => { return string.Format(Resources.Translate("ComponentNameExistInSketchpad"), newName); }) == DialogResult.OK)
                {
                    pad.Name = UIInteraction.Rename.NewName;
                }
            }
        }
        void noPadSelected()
        {
            imageList.Images.Clear();
            for (int i = 0; i < Pads.Count; i++)
            {
                imageList.Images.Add(Pads[i].GetThumbNail());
                Pads[i].ThumbNailItem.ImageIndex = i;
            }
            NoSketchPadSelected?.Invoke();
        }
        void TabControl_IndexChanged(object sender, EventArgs e)
        {
            if (PageContainer.SelectedTab == homePage)
            {
                if (SelectedPad != null)
                {
                    SelectedPad.Deactivate();
                    SelectedPad = null;
                }
                noPadSelected();
            }
            else
            {
                SketchPad pad = PageContainer.SelectedTab.Tag as SketchPad;
                if (!pad.IsActivated)
                {
                    pad.Activate();
                }
            }
        }
        public SketchPad CreateSketchpad(string name, CoordinateSystemType type)
        {
            SketchPad pad = new SketchPad(this, name);
            pad.Activated += (SketchPad sender) =>
            {
                SelectedPad = sender;
            };
            ThumbNailList.Items.Add(pad.ThumbNailItem);
            pad.ChangeCoordinate(type);
            pad.SelectNothing();
            return pad;
        }
        public bool CheckPadNameExist(string name)
        {
            foreach (SketchPad item in Pads)
            {
                if (item.ObjectState == ObjectState.Normal)
                {
                    if (item.Name == name)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        public bool CheckParamNameExist(string name)
        {
            foreach (BasicParameter item in Parameters)
            {
                if (item.ObjectState == ObjectState.Normal)
                {
                    if (item.Name == name)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        public void Activate()
        {
            IsActivated = true;
            switch (DocumentWindow.DockState)
            {
                case DockState.Hidden:
                    if (LinkedFile == null && !string.IsNullOrEmpty(lblLocation.Text))
                    {
                        try
                        {
                            LinkedFile = new FileStream(lblLocation.Text, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message, Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                    break;
            }
            Activated?.Invoke(this);
            if (SelectedPad == null)
            {
                noPadSelected();
            }
            else
            {
                SelectedPad.Activate();
            }
        }
        public bool Save()
        {
            if (LinkedFile == null)
            {
                SaveFileDialog sfd = new SaveFileDialog()
                {
                    Title = $"\"{Title}\"{Resources.Translate("SaveAs")}",
                    Filter = $"{Flags.SoftwareName + Resources.Join + Resources.Translate("Document")}(*{Flags.DocumentExtension})|*{Flags.DocumentExtension}",
                    InitialDirectory = Flags.DesktopPath,
                };
                if (sfd.ShowDialog() == DialogResult.OK)
                {
                    return SaveAs(sfd.FileName);
                }
            }
            else
            {
                return Save(LinkedFile, SaveReason.UserSave);
            }
            return false;
        }
        public bool SaveAs(string fileName)
        {
            if (LinkedFile != null)
            {
                LinkedFile.Close();
                LinkedFile = null;
            }
            try
            {
                LinkedFile = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            return Save(LinkedFile, SaveReason.UserSave);
        }
        public bool Save(Stream fs, SaveReason reason)
        {
            lock (saveLocker)
            {
                if (fs == null) return false;
                Dictionary<string, object> data = new Dictionary<string, object>();
                BeforeSerializing(data);
                IFormatter fmt = new BinaryFormatter();
                try
                {
                    fs.Seek(0, SeekOrigin.Begin);
                    fmt.Serialize(fs, new object[] { this, data });
                    fs.Flush();
                }
                catch (Exception ex)
                {
                    if (reason == SaveReason.UserSave)
                    {
                        MessageBox.Show(ex.Message, Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    return false;
                }
                if (reason == SaveReason.UserSave)
                {
                    Modified = false;
                }
                return true;
            }
        }
        public void BeforeSerializing(Dictionary<string, object> data)
        {
            foreach (SketchPad item in Pads)
            {
                item.BeforeSerializing(data);
            }
            foreach (BasicParameter item in Parameters)
            {
                item.BeforeSerializing(data);
            }
        }
        public void AfterDeserialized(Dictionary<string, object> data)
        {
            documentWindow = new DocumentWindow(this);
            buildHomePage(Title);
            documentsManagerItem = new ListViewItem(new string[] { Title, Remark }) { Tag = this };
            windowMenuItem = new ToolStripMenuItem(Title, null)
            {
                CheckOnClick = true,
                Tag = true,
            };
            Modified = false;
            foreach (SketchPad item in Pads)
            {
                item.AfterDeserialized(data);
            }
            foreach (BasicParameter item in Parameters)
            {
                item.AfterDeserialized(data);
            }
        }
        public void Deactivate()
        {
            IsActivated = false;
            if (SelectedPad == null)
            {

            }
            else
            {
                SelectedPad.Deactivate();
            }
        }
    }
}
